library IEEE;
use IEEE.std_logic_1164.all;
use IEEE.numeric_std.all;

entity controlador is
	port(
		cp, ep, ea, su, eu, clk_out, clr_out: out std_logic := '0';
	   ce_not, lm_not, li_not, ei_not, la_not, lb_not, l0_not, clk_not_out, clr_not_out: out std_logic := '1';
	   instruction: in std_logic_vector (3 downto 0)
	);
end controlador;

architecture a_controlador of controlador is
	signal terminou: std_logic := '0'; -- determina se todos os comandos foram executados e o clock deve parar.
   signal clk, clr: std_logic := '0';
   signal clk_not, clr_not : std_logic := '1';
   signal ring_counter, next_ring_counter: std_logic_vector (5 downto 0) := "000001";
begin

	process
	begin
		if(terminou='0') then
		   wait for 40 ns;
   	 	if (clk='0') then
   	 		clk<='1';
   	 		clk_out<='1';
   	 		clk_not_out<='0';
   	 	else
   	 		clk<='0';
   	 		clk_out<='0';
   	 		clk_not_out<='1';
   		end if;
   	end if;
	end process;

	process (clk,clr,ring_counter,instruction)
   begin
		if (clk'event and clk = '0') then
      	if(ring_counter="000001") then
      		next_ring_counter <= "000010";
      	elsif(ring_counter="000010") then
      		next_ring_counter <= "000100";
      	elsif(ring_counter="000100") then
      		next_ring_counter <= "001000";
      	elsif(ring_counter="001000") then
      		next_ring_counter <= "010000";
      	elsif(ring_counter="010000") then
      		next_ring_counter <= "100000";
      	elsif(ring_counter="100000") then
      		next_ring_counter <= "000001";
      	end if;
       
		-- se for HLT instr, para o processamento
      if (instruction = "1111") then
		  	terminou<='1';
		  	ring_counter<="000000";
		  	next_ring_counter<="000000";
      end if;
        
        	cp <= '0';
		 	ep <= '0';
		 	ea <= '0';
		 	su <= '0';
		 	eu <= '0';
	    	ce_not <= '1';
	    	lm_not <= '1';
	    	li_not <= '1';
	    	ei_not <= '1';
	    	la_not <= '1';
	    	lb_not <= '1';
	    	l0_not <= '1';

      -- t1 a t3 eh ciclo de memoria
      if (ring_counter = "000001") then -- (t1) estado de endereco
         ep <= '1';
         lm_not <= '0';
      elsif (ring_counter = "000010") then -- (t2) estado de incremento
         cp <= '1';
      elsif (ring_counter = "000100") then -- (t3) estado de memoria
         ce_not <= '0';
         li_not <= '0';

      -- t4 a t6 eh ciclo de execucao
      elsif (ring_counter = "001000") then -- (t4) estado de endereco
         -- avalia a instrucao
         if (instruction = "0000") then -- instr LDA
            ei_not <= '0';
            lm_not <= '0';
         elsif (instruction = "0001" or instruction = "0010") then -- instr ADD ou SUB
            ei_not <= '0';
            lm_not <= '0';
         elsif (instruction = "1110") then -- instr OUT
            ea <= '1';
            l0_not <= '0';
         end if;
      elsif (ring_counter = "010000") then -- (t5) estado de endereco
         if (instruction = "0000") then -- instr LDA
            ce_not <= '0';
            la_not <= '0';
         elsif (instruction = "0001" or instruction = "0010") then -- instr ADD ou SUB
            ce_not <= '0';
            lb_not <= '0';
         end if;
      elsif (ring_counter = "100000") then -- (t6) estado de endereco
         
         -- para LDA, todos os sinais sao 0 no t6
         
         if (instruction = "0001") then -- instr ADD
            eu <= '1';
            la_not <= '0';
         elsif (instruction = "0010") then -- instr SUB
            eu <= '1';
            la_not <= '0';
            su <= '1';
          end if;
        end if;
      end if;
      
      ring_counter <= next_ring_counter;
      
      -- limpa o ring counter quando o sinal clr_count eh alto
      if (clr'event and clr = '1') then
        ring_counter <= "000001";
      end if;
	end process;
end a_controlador;
